In [1]:
# windows only hack for graphviz path 
import os
for path in os.environ['PATH'].split(os.pathsep):
    if path.endswith("Library\\bin"):
        os.environ['PATH']+=os.pathsep+os.path.join(path, 'graphviz')

In [2]:
import tensorflow as tf
import numpy as np

# 下面兩個是用來輔助圖形化
from IPython.display import display
from tfdot import tfdot

常數及節點


In [3]:
tf.constant(42)


Out[3]:
<tf.Tensor 'Const:0' shape=() dtype=int32>

In [4]:
tf.constant(42.)


Out[4]:
<tf.Tensor 'Const_1:0' shape=() dtype=float32>

In [5]:
tf.constant([42])


Out[5]:
<tf.Tensor 'Const_2:0' shape=(1,) dtype=int32>

In [6]:
matrix1 = tf.constant([[3., 3.]])

matrix2 = tf.constant([[2.],[2.]])

matrix1, matrix2


Out[6]:
(<tf.Tensor 'Const_3:0' shape=(1, 2) dtype=float32>,
 <tf.Tensor 'Const_4:0' shape=(2, 1) dtype=float32>)

In [7]:
product = tf.matmul(matrix1, matrix2)
product


Out[7]:
<tf.Tensor 'MatMul:0' shape=(1, 1) dtype=float32>

In [8]:
tfdot()


Out[8]:
root Const Const: Const output: () int32 Const_1 Const: Const_1 output: () float32 Const_2 Const: Const_2 output: (1,) int32 Const_3 Const: Const_3 output: (1, 2) float32 MatMul MatMul: MatMul output: (1, 1) float32 Const_3->MatMul Const_4 Const: Const_4 output: (2, 1) float32 Const_4->MatMul

這些東西的單位叫做 graph


In [9]:
graph = tf.get_default_graph()
graph


Out[9]:
<tensorflow.python.framework.ops.Graph at 0x276dd4462b0>

In [10]:
product.graph


Out[10]:
<tensorflow.python.framework.ops.Graph at 0x276dd4462b0>

In [11]:
# 從 graph 得到 tensor
graph.get_tensor_by_name('MatMul:0')


Out[11]:
<tf.Tensor 'MatMul:0' shape=(1, 1) dtype=float32>

Q:

試試看其他名稱

Operator


In [12]:
graph.get_operations()


Out[12]:
[<tf.Operation 'Const' type=Const>,
 <tf.Operation 'Const_1' type=Const>,
 <tf.Operation 'Const_2' type=Const>,
 <tf.Operation 'Const_3' type=Const>,
 <tf.Operation 'Const_4' type=Const>,
 <tf.Operation 'MatMul' type=MatMul>]

In [13]:
product.op


Out[13]:
<tf.Operation 'MatMul' type=MatMul>

In [14]:
# 運算的輸出節點
product.op.outputs


Out[14]:
[<tf.Tensor 'MatMul:0' shape=(1, 1) dtype=float32>]

In [15]:
# 運算的輸入節點
list(product.op.inputs)


Out[15]:
[<tf.Tensor 'Const_3:0' shape=(1, 2) dtype=float32>,
 <tf.Tensor 'Const_4:0' shape=(2, 1) dtype=float32>]

Q

  • 試試看將 numpy ndarray 轉成 tf.constant
  • 建立一個 matrix1 和 matrix2 逐項相乘的節點(猜一下是 tf.什麼)
  • tf.reset_default_graph() 清掉 default graph 看看,會發生什麼事情?
  • 再跑一下 tfdot 看看

In [16]:
# 建立逐項相乘的參考方式
%run -i q_constant_mul.py
# 用
# %load q_constant_mul.py
# 可以看內容


Tensor("Mul:0", shape=(2, 2), dtype=float32)
root Const Const: Const output: () int32 Const_1 Const: Const_1 output: () float32 Const_2 Const: Const_2 output: (1,) int32 Const_3 Const: Const_3 output: (1, 2) float32 MatMul MatMul: MatMul output: (1, 1) float32 Const_3->MatMul Mul Mul: Mul output: (2, 2) float32 Const_3->Mul Const_4 Const: Const_4 output: (2, 1) float32 Const_4->MatMul Const_4->Mul

Session

如果圖是靜態的描述操作,動態的狀態就是 Session


In [17]:
# 建立一個 Session
sess = tf.Session()
# 在這個 Session 中執行 product 並且印出結果。
print(sess.run(product))
# 結束這個 Session
sess.close()


[[ 12.]]

也可以用 context manager 的寫法


In [18]:
with tf.Session() as sess:
    print(sess.run(product))
    # 也可以用
    print(product.eval())


[[ 12.]]
[[ 12.]]

Q

  • 用 numpy 檢查結果
  • 把前面所有的 operation 都跑一遍

In [19]:
# 計算所有結果
%run -i q_run_all_op.py


Const [42]
Const_1 [42.0]
Const_2 [array([42])]
Const_3 [array([[ 3.,  3.]], dtype=float32)]
Const_4 [array([[ 2.],
       [ 2.]], dtype=float32)]
MatMul [array([[ 12.]], dtype=float32)]
Mul [array([[ 6.,  6.],
       [ 6.,  6.]], dtype=float32)]

Device context

可以設定 device context


In [20]:
with tf.Session() as sess:
    with tf.device("/cpu:0"):
        print(sess.run(product))


[[ 12.]]

Q

清掉前面的 default graph, 然後用不同的方式來計算 $1+2+\cdots+10$

  • 用公式 $10\cdot(10+1)/2$
  • tf.reduce_sum
  • tf.add_n
  • tf.matmul
  • 用 python 迴圈建立 graph

In [21]:
# 參考答案
%run -i q_sum.py


reduce_sum 55
root one_to_ten Const: one_to_ten output: (10,) int32 Sum Sum: Sum output: () int32 one_to_ten->Sum Const Const: Const output: (1,) int32 Const->Sum
add_n 55
root Const Const: Const output: () int32 AddN AddN: AddN output: () int32 Const->AddN Const_1 Const: Const_1 output: () int32 Const_1->AddN Const_2 Const: Const_2 output: () int32 Const_2->AddN Const_3 Const: Const_3 output: () int32 Const_3->AddN Const_4 Const: Const_4 output: () int32 Const_4->AddN Const_5 Const: Const_5 output: () int32 Const_5->AddN Const_6 Const: Const_6 output: () int32 Const_6->AddN Const_7 Const: Const_7 output: () int32 Const_7->AddN Const_8 Const: Const_8 output: () int32 Const_8->AddN Const_9 Const: Const_9 output: () int32 Const_9->AddN
formula 55
root cluster_Add Add cluster_floordiv floordiv Add/y Const: y output: () int32 Add Add: Add output: () int32 Add/y->Add floordiv/y Const: y output: () int32 floordiv FloorDiv: floordiv output: () int32 floordiv/y->floordiv ten Const: ten output: () int32 ten->Add mul Mul: mul output: () int32 ten->mul Add->mul mul->floordiv
matmul [[ 55.]]
root cluster_MatMul MatMul MatMul/a Const: a output: (1, 10) float32 MatMul MatMul: MatMul output: (1, 1) float32 MatMul/a->MatMul ones Const: ones output: (10, 1) float32 ones->MatMul
loop 55
root cluster_Add_4 Add_4 cluster_Add Add cluster_Add_6 Add_6 cluster_Add_8 Add_8 cluster_Add_3 Add_3 cluster_Add_7 Add_7 cluster_Add_2 Add_2 cluster_Add_5 Add_5 cluster_Add_1 Add_1 Add_4/y Const: y output: () int32 Add_4 Add: Add_4 output: () int32 Add_4/y->Add_4 Add_3/y Const: y output: () int32 Add_3 Add: Add_3 output: () int32 Add_3/y->Add_3 Add/y Const: y output: () int32 Add Add: Add output: () int32 Add/y->Add Add_6/y Const: y output: () int32 Add_6 Add: Add_6 output: () int32 Add_6/y->Add_6 Add_8/y Const: y output: () int32 Add_8 Add: Add_8 output: () int32 Add_8/y->Add_8 Add_7/y Const: y output: () int32 Add_7 Add: Add_7 output: () int32 Add_7/y->Add_7 Add_2/y Const: y output: () int32 Add_2 Add: Add_2 output: () int32 Add_2/y->Add_2 Add_1/y Const: y output: () int32 Add_1 Add: Add_1 output: () int32 Add_1/y->Add_1 Add_5/y Const: y output: () int32 Add_5 Add: Add_5 output: () int32 Add_5/y->Add_5 Const Const: Const output: () int32 Const->Add Add->Add_1 Add_1->Add_2 Add_2->Add_3 Add_3->Add_4 Add_4->Add_5 Add_5->Add_6 Add_6->Add_7 Add_7->Add_8

Interactive session

在 notebook 中,可以用 interactive session, 就不用特別指名 session 了。 比較方便。


In [22]:
# 重新設定環境
tf.reset_default_graph()
# 設定 default session
sess =  tf.InteractiveSession()

常數太無聊, 試試看可以改變輸入的運算


In [23]:
# place holder, 先佔位子
a = tf.placeholder(tf.float32, name="this_is_a")
b = tf.placeholder(tf.float32, name="this_is_b")
s = tf.add(a, b)
display(tfdot())
s


root this_is_a Placeholder: this_is_a output: <unknown> float32 Add Add: Add output: <unknown> float32 this_is_a->Add this_is_b Placeholder: this_is_b output: <unknown> float32 this_is_b->Add
Out[23]:
<tf.Tensor 'Add:0' shape=<unknown> dtype=float32>

直接執行

s.eval()

會爆掉,因為佔了位子沒人來

所以要放東西進去


In [24]:
s.eval({a:2, b: 5})


Out[24]:
7.0

或者


In [25]:
sess.run(s, {a:[1,2], b:[3,4]})


Out[25]:
array([ 4.,  6.], dtype=float32)

In [26]:
sess.close()

Variable

傳遞資訊不是免費的

變數:存東西在 session 的空間


In [27]:
# 重新設定 graph 環境和 default session
tf.reset_default_graph()
sess = tf.InteractiveSession()
# 計數器
state = tf.Variable(0, name="state")

# 新的節點 計數器+1
new_value =  tf.add(state, tf.constant(1, name='one'), name='new_value')
# 更新 state
update = tf.assign(state, new_value)
# 變數初始化,這也是一個節點
init_op = tf.global_variables_initializer()
tfdot()


Out[27]:
root cluster_state state state/initial_value Const: initial_value output: () int32 state/Assign Assign: Assign output: () int32_ref state/initial_value->state/Assign state VariableV2: state output: () int32_ref state/Assign->state state/read Identity: read output: () int32 new_value Add: new_value output: () int32 state/read->new_value state->state/read one Const: one output: () int32 one->new_value Assign Assign: Assign output: () int32_ref new_value->Assign Assign->state init NoOp: init

上面都是靜態的,下面才開始在 session 中執行


In [28]:
init_op.run()
# or sess.run(init_op)
print(state.eval())


0

In [29]:
for _ in range(300):
    #執行更新
    print(update.eval())


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300

In [30]:
state.eval()


Out[30]:
300

In [31]:
sess.run([update]*10)


Out[31]:
[301, 301, 301, 301, 301, 301, 301, 301, 301, 301]

In [32]:
sess.close()

Initialize from another variable


In [33]:
# 重設環境
tf.reset_default_graph()
sess = tf.InteractiveSession()

# 第一個變數 weights
weights = tf.Variable(tf.random_normal((10,), stddev=0.35), name='weights')
# 想要讓 w2 的初始值設定成和 weights 一樣 
w1 = tf.Variable(weights.initialized_value(), name ='w1')
# 想將 w_twice 設定為 weights 的兩倍
w2 = tf.Variable(weights.initialized_value()*tf.constant(2., name='two'), name="w2")
tfdot()


Out[33]:
root cluster_w2 w2 cluster_w1 w1 cluster_weights weights cluster_random_normal random_normal w2/Assign Assign: Assign output: (10,) float32_ref w2 VariableV2: w2 output: (10,) float32_ref w2/Assign->w2 w2/read Identity: read output: (10,) float32 w1/Assign Assign: Assign output: (10,) float32_ref w1 VariableV2: w1 output: (10,) float32_ref w1/Assign->w1 w1/read Identity: read output: (10,) float32 weights/Assign Assign: Assign output: (10,) float32_ref weights VariableV2: weights output: (10,) float32_ref weights/Assign->weights weights/read Identity: read output: (10,) float32 random_normal/shape Const: shape output: (1,) int32 random_normal/RandomStandardNormal RandomStandardNormal: RandomStandardNormal output: (10,) float32 random_normal/shape->random_normal/RandomStandardNormal random_normal/mean Const: mean output: () float32 random_normal Add: random_normal output: (10,) float32 random_normal/mean->random_normal random_normal/stddev Const: stddev output: () float32 random_normal/mul Mul: mul output: (10,) float32 random_normal/stddev->random_normal/mul random_normal/RandomStandardNormal->random_normal/mul random_normal/mul->random_normal random_normal->weights/Assign weights->weights/read Identity Identity: Identity output: (10,) float32 weights->Identity Identity_1 Identity: Identity_1 output: (10,) float32 weights->Identity_1 Identity->w1/Assign w1->w1/read mul Mul: mul output: (10,) float32 Identity_1->mul two Const: two output: () float32 two->mul mul->w2/Assign w2->w2/read

In [34]:
init_op = tf.global_variables_initializer()
init_op.run()

for v in tf.global_variables():
    print(v.name, v)
    print(v.eval())


weights:0 Tensor("weights/read:0", shape=(10,), dtype=float32)
[-0.22638819  0.2929033  -0.51664144  0.79778254 -0.37592012  0.23500675
 -0.16974309 -0.18892676 -0.11067705 -0.03066515]
w1:0 Tensor("w1/read:0", shape=(10,), dtype=float32)
[-0.22638819  0.2929033  -0.51664144  0.79778254 -0.37592012  0.23500675
 -0.16974309 -0.18892676 -0.11067705 -0.03066515]
w2:0 Tensor("w2/read:0", shape=(10,), dtype=float32)
[-0.45277637  0.58580661 -1.03328288  1.59556508 -0.75184023  0.4700135
 -0.33948618 -0.37785351 -0.2213541  -0.0613303 ]

In [35]:
sess.close()